import { getCurrentInstance } from "@vue/runtime-core";
import { createEvents } from "src/plugins/Event";
import { SimpleFunction } from "src/shims";
import { kebabCase } from "src/utils/kebabCase";

function emitNameToListenName(emitName: string) {
  const match = emitName.match(/update([A-Z])(.*)/);
  if (match) {
    return `update:${match[1].toLowerCase()}${match[2]}`;
  } else {
    return kebabCase(emitName)!;
  }
}

type EventListener<EmitValue> = EmitValue extends (...args: any[]) => any
  ? Parameters<EmitValue>
  : never;

export type ComponentEvent<Emit> = {
  emit: { [key in keyof Emit]: (...args: EventListener<Emit[key]>) => void };
  on: { [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void };
  once: {
    [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void;
  };
  off: { [key in keyof Emit]: (cb: (...args: EventListener<Emit[key]>) => void) => void };
};

export function getComponentEmit<T>(emitObject: T): T {
    
  return {
    change: null,
    ...Object.keys(emitObject || {}).reduce((ret: any, key: string) => {
      ret[emitNameToListenName(key)] = (emitObject as any)[key];
      return ret;
    }, {} as any)
  };
}

export function useEvent<T>(emitObject: T) {
  const ctx = getCurrentInstance()!;
  const event = createEvents();

  const emit = {} as any;
  const on = {} as any;
  const once = {} as any;
  const off = {} as any;

  Object.keys(emitObject || {}).forEach(key => {
    const kebabCaseName = emitNameToListenName(key);
    emit[key] = (...args: any[]) => {
      ctx.emit(kebabCaseName, ...args);
      event.emit(key, ...args);
      if (key === "updateModelValue") {
        ctx.emit("change", ...args);
        event.emit("change", ...args);
      }
    };
    on[key] = (fn: SimpleFunction) => event.on(kebabCaseName, fn);
    once[key] = (fn: SimpleFunction) => event.on(kebabCaseName, fn);
    off[key] = (fn: SimpleFunction) => event.on(kebabCaseName, fn);
  });

  return {
    emit,
    on,
    once,
    off
  };
}
